﻿using System.Linq.Expressions;
using wwl.Contract.Dtos.Common;
using wwl.Domain.Entities.Common;

namespace wwl.Contract.Interfaces.Common
{
  /// <summary>
  /// 领域实体的通用仓储接口，定义所有实体的基础数据操作契约
  /// 采用泛型设计，支持所有继承自 <see cref="BaseEntity"/> 的领域实体
  /// </summary>
  /// <typeparam name="T">领域实体类型，必须继承自 <see cref="BaseEntity"/>（确保实体包含ID等公共属性）</typeparam>
  public interface IGenericRepository<T> where T : BaseEntity
  {     
      /// <summary>
      /// 根据ID异步查询单个实体
      /// </summary>
      /// <param name="id">实体唯一标识（对应 <see cref="BaseEntity.Id"/>）</param>
      /// <returns>
      /// 找到则返回实体对象（<typeparamref name="T"/>），未找到则返回 null
      /// 采用可空类型（T?）避免空引用异常
      /// </returns>
      Task<T?> GetByIdAsync(string id);

      /// <summary>
      /// 异步新增实体
      /// </summary>
      /// <param name="entity">待新增的实体对象（需确保包含必要的业务字段）</param>
      /// <returns>新增后的实体（通常包含数据库自动生成的ID、创建时间等字段）</returns>
      /// <remarks>
      /// 此方法仅将实体添加到数据上下文，需调用 SaveChanges 相关方法提交到数据库
      /// </remarks>
      Task<T> AddAsync(T entity);

      /// <summary>
      /// 异步更新实体
      /// </summary>
      /// <param name="entity">待更新的实体对象（需包含有效ID以定位数据）</param>
      /// <returns>更新后的实体（反映最新状态）</returns>
      /// <remarks>
      /// 此方法仅标记实体为修改状态，需调用 SaveChanges 相关方法提交到数据库
      /// </remarks>
      Task<T> UpdateAsync(T entity);

      /// <summary>
      /// 异步物理删除实体（从数据库中彻底移除记录）
      /// </summary>
      /// <param name="id">实体唯一标识</param>
      /// <returns>删除成功返回 true；若实体不存在，返回 false</returns>
      /// <remarks>
      /// 物理删除不可逆，适用于无需保留历史数据的场景
      /// 操作需调用 SaveChanges 相关方法生效
      /// </remarks>
      Task<bool> DeleteAsync(string id);

      /// <summary>
      /// 异步逻辑删除实体（仅标记删除状态，不实际移除记录）
      /// </summary>
      /// <param name="id">实体唯一标识</param>
      /// <returns>标记成功返回 true；若实体不存在，返回 false</returns>
      /// <remarks>
      /// 通常通过设置 <see cref="BaseEntity.IsDeleted"/> 等字段实现，支持数据恢复
      /// 操作需调用 SaveChanges 相关方法生效
      /// </remarks>
      Task<bool> SoftDeleteAsync(string id);

      /// <summary>
      /// 获取实体的可查询集合（开启变更跟踪）
      /// </summary>
      /// <returns>可拼接查询条件的 <see cref="IQueryable{T}"/> 对象</returns>
      /// <remarks>
      /// 变更跟踪（Change Tracking）会监控实体状态变化，适合查询后需要修改的场景
      /// 性能略低于无跟踪查询，谨慎用于高频只读场景
      /// </remarks>
      IQueryable<T> Query();

      /// <summary>
      /// 获取实体的可查询集合（关闭变更跟踪）
      /// </summary>
      /// <returns>可拼接查询条件的 <see cref="IQueryable{T}"/> 对象</returns>
      /// <remarks>
      /// 无跟踪查询（No Tracking）不监控实体状态，性能更优，适合仅读取数据的场景（如列表展示）
      /// 若查询后需修改实体，需手动附加到上下文
      /// </remarks>
      IQueryable<T> QueryNoTracking();

      /// <summary>
      /// 异步执行带筛选条件的分页查询
      /// </summary>
      /// <param name="request">分页参数（包含页码 PageIndex、每页条数 PageSize）</param>
      /// <param name="filter">可选的筛选条件表达式（如 t => t.IsActive），为 null 时查询所有</param>
      /// <returns>
      /// 分页结果对象 <see cref="PagedResult{T}"/>，包含：
      /// - Total：符合条件的总记录数
      /// - Items：当前页的实体列表
      /// </returns>
      /// <remarks>
      /// 内部自动处理分页逻辑（Skip + Take），并计算总条数
      /// 建议结合 <see cref="QueryNoTracking"/> 提升查询性能（默认实现通常采用无跟踪）
      /// </remarks>
      Task<PagedResult<T>> GetPagedAsync(PagedRequest request, Expression<Func<T, bool>>? filter = null);
    }
}
